package com.onpositive.wiki3.db.catmodel;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;

import com.carrotsearch.hppc.IntOpenHashSet;
import com.onpositive.nlp.sequence.ClassifiedSequence;
import com.onpositive.nlp.sequence.SequenceParser;
import com.onpositive.nlp.sequence.WikiLookup;
import com.onpositive.wiki3.db.IWikiDB;

/**
 * 
 * @author kor
 * 
 */
public final class Category implements ICategory {

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + id;
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Category other = (Category) obj;
		if (id != other.id)
			return false;
		return true;
	}

	private static final int[] INTS = new int[0];

	int id;
	int tag;

	public int getTag() {
		return tag;
	}

	public void setTag(int tag) {
		this.tag = tag;
	}

	int distance = Integer.MAX_VALUE;
	int deepsize = Integer.MIN_VALUE;

	protected IntOpenHashSet parents;

	int pId = -1;

	protected IntOpenHashSet childs;
	int cId = -1;

	private Categories cat;

	public Category(int id, Categories cat) {
		this.id = id;
		this.cat = cat;
	}

	public void addParent(int parent) {
		if (pId == -1 || pId == parent) {
			pId = parent;
			return;
		}
		if (parents == null) {
			parents = new IntOpenHashSet();
			parents.add(pId);
		}
		parents.add(parent);
	}

	public void addChild(int parent) {
		if (cId == -1 || cId == parent) {
			cId = parent;
			return;
		}
		if (childs == null) {
			childs = new IntOpenHashSet();
			childs.add(cId);
		}
		childs.add(parent);

	}

	void removeParent(int i) {
		if (parents != null) {
			parents.remove(i);
			if (parents.size() == 1) {
				pId = parents.iterator().next().value;
				parents = null;
			}
			return;
		}
		pId = -1;
	}

	void removeChild(int i) {
		if (childs != null) {
			childs.remove(i);
			if (childs.size() == 1) {
				cId = childs.iterator().next().value;
				childs = null;
			}
			return;
		}
		cId = -1;
	}

	public int parentCount() {
		if (pId == -1) {
			return 0;
		}
		if (parents != null) {
			return parents.size();
		}
		return 1;
	}

	public int[] getChildren() {
		if (childs == null && cId != -1) {
			return new int[] { cId };
		}
		if (childs != null) {
			return childs.toArray();
		}
		return INTS;
	}

	public int[] getParents() {
		if (parents == null && pId != -1) {
			return new int[] { pId };
		}
		if (parents != null) {
			return parents.toArray();
		}
		return INTS;
	}

	public int childCount() {
		if (cId == -1) {
			return 0;
		}
		if (childs != null) {
			return childs.size();
		}
		return 1;
	}

	public boolean hasChild(int parent) {
		if (cId == parent) {
			return true;
		}
		if (childs != null) {
			return childs.contains(parent);
		}
		return false;
	}

	public boolean hasParent(int parent) {
		if (pId == parent) {
			return true;
		}
		if (parents != null) {
			return parents.contains(parent);
		}
		return false;
	}

	public int id() {
		return id;
	}

	public String getTitle(IWikiDB db) {
		try {
			return db.getTitleMapper().getTitle(id);// .toLowerCase().replace(' ',
													// '_');
		} catch (Exception e) {
			return e.getMessage();
			// TODO: handle exception
		}
	}

	public boolean hasChildren() {
		return childCount() > 0;
	}

	public int distance() {
		return distance;
	}

	protected String title;

	@Override
	public String toString() {
		if (title != null) {
			return title;
		}
		String title2 = getTitle(cat.getDb());
		this.title = title2;
		return title2;
	}

	public Category[] getChildCategories() {
		int[] children = getChildren();
		Category[] p = new Category[children.length];
		for (int a = 0; a < children.length; a++) {
			p[a] = cat.get(children[a]);
		}
		return p;
	}

	public Category getParent(int i) {
		int[] parents2 = getParents();
		return cat.get(parents2[i]);
	}

	public void replaceOn(Category parent) {
		cat.replaceAll(this.id, parent.id);
	}

	public void remove() {
		cat.removeCategory(this.id);
	}

	public void removeCategoryWithProxy() {
		cat.removeCategoryWithProxy(this.id);
	}

	public boolean hasParent(int id, int i) {
		return cat.hasParent(this, id, i);
	}

	public Category[] getParentsCategories() {
		int[] children = getParents();
		Category[] p = new Category[children.length];
		for (int a = 0; a < children.length; a++) {
			p[a] = cat.get(children[a]);
		}
		return p;
	}

	public boolean hasParent(Category st, int level) {
		return cat.hasParent(this, st.id, level);
	}

	public void unregisterChild(Category st) {
		cat.unregisterChild(this.id, st.id);
	}

	public void registerChild(Category st) {
		cat.registerChild(this.id, st.id);
	}

	public void unregisterParent(Category st) {
		cat.unregisterChild(st.id, this.id);
	}

	public void registerParent(Category st) {
		cat.registerChild(st.id, this.id);
	}

	public int deepSize() {
		if (deepsize != Integer.MIN_VALUE) {
			return deepsize;
		}
		int deepSize2 = deepSize(new IntOpenHashSet());
		deepsize = deepSize2;
		return deepSize2;
	}

	public int deepSize(IntOpenHashSet mm) {

		int r = 1;
		if (mm.contains(this.id)) {
			return -1;
		}
		mm.add(this.id);
		for (Category c : getChildCategories()) {

			IntOpenHashSet mm2 = new IntOpenHashSet();
			mm2.addAll(mm);
			int deepSize = dg(c, mm2);
			if (deepSize == -1) {
				return -1;
			}
			r += deepSize;
		}
		return r;
	}

	protected int dg(Category c, IntOpenHashSet mm2) {
		if (c.deepsize != Integer.MIN_VALUE) {
			return c.deepsize;
		}
		return c.deepSize(mm2);
	}

	public ArrayList<Category> getRootPath() {
		for (Category m : getParentsCategories()) {
			if (m.distance < this.distance) {

			}
		}
		return null;
	}

	public Categories getStore() {
		return cat;
	}

	public Set<Category> getAllParents() {
		HashSet<Category> m = new HashSet<Category>();
		Category[] parentsCategories = getParentsCategories();
		for (Category c : parentsCategories) {
			m.addAll(c.getAllParents());
			m.add(c);
		}
		return m;
	}
	
	public Set<Category> getAllParents(int q) {
		HashSet<Category> m = new HashSet<Category>();
		Category[] parentsCategories = getParentsCategories();
		for (Category c : parentsCategories) {
			if (q<5){
			m.addAll(c.getAllParents(q+1));
			m.add(c);
			}
		}
		return m;
	}

	public Set<Category> getAllChildren() {
		HashSet<Category> m = new HashSet<Category>();
		Category[] parentsCategories = getChildCategories();
		for (Category c : parentsCategories) {
			m.addAll(c.getAllChildren(0));
			m.add(c);
		}
		return m;
	}

	public Set<Category> getAllChildren(int q) {
		HashSet<Category> m = new HashSet<Category>();
		Category[] parentsCategories = getChildCategories();
		for (Category c : parentsCategories) {
			if (q < 5) {
				m.addAll(c.getAllChildren(q + 1));
				m.add(c);
			}
		}
		return m;
	}

	protected ClassifiedSequence sequence;

	public ClassifiedSequence getSequnce() {
		if (sequence == null) {
			String string = toString();
			ClassifiedSequence parse = SequenceParser.parse(string,
					new WikiLookup(string, cat.getDb().getTitleMapper()));
			sequence = parse;
		}
		return sequence;
	}

	public String[] getTokens() {
		String string = toString();
		String[] sequnce = string.split("_");
		return sequnce;
	}
	
	
}
